package utils;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 传入参数LocalData
 * 判断当天是工作日还是非工作日
 * 1为工作日，0为节假日
 *
 * 可对工作日历进行单独或批量设置
 * 且自定义日期优先于默认类型
 */
public class WorkCalendar {
    private static final String HOLIDAY_API = "http://timor.tech/api/holiday/year/";
    private final Map<String, Integer> holidayCache = new HashMap<>();
    private int currentYear = -1;
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private final Map<String, Integer> customHolidayCache = new HashMap<>();

    /**
     * 检查指定日期是否为工作日
     * @param date LocalDate类型的日期
     * @return 1-工作日，0-节假日
     */
    public int isWorkDay(LocalDate date) {
        String dateStr = date.format(formatter);
        // 首先检查自定义日期
        if (customHolidayCache.containsKey(dateStr)) {
            return customHolidayCache.get(dateStr);
        }

        int year = date.getYear();
        // 修改日期格式，只保留月份和日期
        String monthDayStr = String.format("%02d-%02d", date.getMonthValue(), date.getDayOfMonth());

        // 如果年份变化或缓存为空，重新获取数据
        if (year != currentYear || holidayCache.isEmpty()) {
            System.out.println();
            syncYearData(year);
        }

        // 从缓存中获取结果
        return holidayCache.getOrDefault(monthDayStr, getDefaultWorkDayStatus(date));
    }

    /**
     * 同步指定年份的节假日数据
     */
    private void syncYearData(int year) {
        try {
            String response = getHolidayData(year);
            parseAndCacheResponse(response);
            currentYear = year;
        } catch (Exception e) {
            System.err.println("获取节假日数据失败：" + e.getMessage());
        }
    }

    /**
     * 调用API获取节假日数据
     */
    private String getHolidayData(int year) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(HOLIDAY_API + year);
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                return EntityUtils.toString(response.getEntity());
            }
        }
    }

    /**
     * 解析API响应并缓存数据
     */
    @SuppressWarnings("unchecked")
    private void parseAndCacheResponse(String response) {
        try {
            Map<String, Object> result = objectMapper.readValue(response, Map.class);
            if (result.get("code").equals(0)) {
                Map<String, Object> holidays = (Map<String, Object>) result.get("holiday");
                if (holidays != null) {
                    holidays.forEach((date, details) -> {
                        try {
                            Map<String, Object> holiday = (Map<String, Object>) details;
                            boolean isHoliday = (boolean) holiday.get("holiday");
                            String type = (String) holiday.get("type");
                            String name = (String) holiday.get("name");

                            int workDayStatus;
                            if (isHoliday || "holiday".equals(type)) {
                                workDayStatus = 0; // 节假日
                            } else {
                                workDayStatus = 1; // 工作日
                            }

                            holidayCache.put(date, workDayStatus);
                        } catch (Exception e) {
                            System.err.println("解析日期 " + date + " 数据失败：" + e.getMessage());
                        }
                    });
                }
            }
        } catch (Exception e) {
            System.err.println("解析节假日数据失败：" + e.getMessage());
        }
    }

    /**
     * 获取默认的工作日状态（周末为节假日，工作日为正常工作日）
     */
    private int getDefaultWorkDayStatus(LocalDate date) {
        switch (date.getDayOfWeek()) {
            case SATURDAY:
            case SUNDAY:
                return 0;
            default:
                return 1;
        }
    }

    /**
     * 添加自定义工作日
     * @param date 要设置为工作日的日期
     * @return true-设置成功，false-设置失败
     */
    public boolean setCustomWorkDay(LocalDate date) {
        if (date == null) {
            return false;
        }
        customHolidayCache.put(date.format(formatter), 1);
        return true;
    }

    /**
     * 添加自定义节假日
     * @param date 要设置为节假日的日期
     * @return true-设置成功，false-设置失败
     */
    public boolean setCustomHoliday(LocalDate date) {
        if (date == null) {
            return false;
        }
        customHolidayCache.put(date.format(formatter), 0);
        return true;
    }

    /**
     * 移除自定义日期设置
     * @param date 要移除设置的日期
     * @return true-移除成功，false-移除失败
     */
    public boolean removeCustomDate(LocalDate date) {
        if (date == null) {
            return false;
        }
        return customHolidayCache.remove(date.format(formatter)) != null;
    }

    /**
     * 批量设置自定义工作日
     * @param dates 要设置为工作日的日期列表
     * @return 成功设置的日期数量
     */
    public int setCustomWorkDays(LocalDate... dates) {
        int count = 0;
        for (LocalDate date : dates) {
            if (setCustomWorkDay(date)) {
                count++;
            }
        }
        return count;
    }

    /**
     * 批量设置自定义节假日
     * @param dates 要设置为节假日的日期列表
     * @return 成功设置的日期数量
     */
    public int setCustomHolidays(LocalDate... dates) {
        int count = 0;
        for (LocalDate date : dates) {
            if (setCustomHoliday(date)) {
                count++;
            }
        }
        return count;
    }

    public int calculateWorkingDays(int year, int month) {
        LocalDate firstDayOfMonth = LocalDate.of(year, month, 1);
        LocalDate lastDayOfMonth = firstDayOfMonth.withDayOfMonth(firstDayOfMonth.lengthOfMonth());

        int workingDays = 0;
        LocalDate currentDate = firstDayOfMonth;

        while (!currentDate.isAfter(lastDayOfMonth)) {
            if (isWorkDay(currentDate) == 1) {
                workingDays++;
            }
            currentDate = currentDate.plusDays(1);
        }

        return workingDays;
    }

    /**
     * 清除所有自定义日期设置
     */
    public void clearCustomDates() {
        customHolidayCache.clear();
    }
}
